#region Using Statements
using System;
using System.Xml;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.Remoting;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
#endregion

namespace SkyBurner
{
    #region ParticleEmitterConfig class
    public class ParticleEmitterConfig
    {
        #region Properties
        private String m_emitterName;
        public String Name
        {
            get { return m_emitterName; }
        }

        private String m_classHandler;
        public String ClassHandler
        {
            get { return m_classHandler; }
        }

        private float m_fParticleSize;
        public float ParticleSize
        {
            get { return m_fParticleSize; }
            set { m_fParticleSize = value; }
        }

        private float m_fParticleLife;
        public float ParticleLife
        {
            get { return m_fParticleLife; }
            set { m_fParticleLife = value; }
        }

        private float m_fParticleSpeed;
        public float ParticleSpeed
        {
            get { return m_fParticleSpeed; }
            set { m_fParticleSpeed = value; }
        }

        private String m_particleTextureName;
        public String ParticleTextureName
        {
            get { return m_particleTextureName; }
            set { m_particleTextureName = value; }
        }

        private float m_fParticleEmitInterval;
        public float ParticleEmitInterval
        {
            get { return m_fParticleEmitInterval; }
            set { m_fParticleEmitInterval = value; }
        }

        private int m_nMaxParticleCount;
        public int MaxParticleCount
        {
            get { return m_nMaxParticleCount; }
            set { m_nMaxParticleCount = value; }
        }

        private int m_nParticlePerFrame;
        public int ParticlePerFrame
        {
            get { return m_nParticlePerFrame; }
            set { m_nParticlePerFrame = value; }
        }

        private bool m_bLoop;
        public bool Loop
        {
            get { return m_bLoop; }
            set { m_bLoop = value; }
        }

        private float m_fKillAfter;
        public float KillAfter
        {
            get { return m_fKillAfter; }
        }
        #endregion

        public ParticleEmitterConfig(XmlNode pXmlConfigNode)
        {
            XMLPropertyBag xmlConfigBag = new XMLPropertyBag(pXmlConfigNode);

            m_emitterName = xmlConfigBag.GetValue<String>("Name", XMLPropertyBagValueType.vtString);
            m_classHandler = xmlConfigBag.GetValue<String>("ClassHandler", XMLPropertyBagValueType.vtString);
            m_fParticleSize = xmlConfigBag.GetValue<float>("Size", XMLPropertyBagValueType.vtFloat);
            m_fParticleLife = xmlConfigBag.GetValue<float>("Life", XMLPropertyBagValueType.vtFloat);
            m_fParticleSpeed = xmlConfigBag.GetValue<float>("Speed", XMLPropertyBagValueType.vtFloat);
            m_particleTextureName = xmlConfigBag.GetValue<String>("Texture", XMLPropertyBagValueType.vtString);
            m_fParticleEmitInterval = xmlConfigBag.GetValue<float>("EmitInterval", XMLPropertyBagValueType.vtFloat);
            m_nMaxParticleCount = xmlConfigBag.GetValue<int>("MaxCount", XMLPropertyBagValueType.vtInteger);
            m_nParticlePerFrame = xmlConfigBag.GetValue<int>("ParticlePerFrame", XMLPropertyBagValueType.vtInteger);
            m_bLoop = (xmlConfigBag.GetValue<int>("Loop", XMLPropertyBagValueType.vtInteger) != 0);
            m_fKillAfter = xmlConfigBag.GetValue<float>("KillAfter", XMLPropertyBagValueType.vtFloat);
        }
    }
    #endregion

    public partial class ParticleSystemManager : BaseDrawableObject
    {
        private SortedList<String, ParticleEmitterConfig> m_particleEmitterConfigs = new SortedList<String, ParticleEmitterConfig>();
        private Collection<ParticleEmitterBase> m_particleEmitterList = new Collection<ParticleEmitterBase>();

        public ParticleSystemManager(BaseGame game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        public void Load(String pXMLEmittersConfigFile)
        {
            XmlDocument xmlEmittersConfig = new XmlDocument();

            try
            {
                xmlEmittersConfig.Load(pXMLEmittersConfigFile);

                foreach (XmlNode emitterNode in xmlEmittersConfig.DocumentElement)
                {
                    ParticleEmitterConfig emitterConfig = new ParticleEmitterConfig(emitterNode);
                    m_particleEmitterConfigs.Add(emitterConfig.Name, emitterConfig);
                }               
            }
            catch (Exception e)
            {
                throw e;
            }
        }

        public ParticleEmitterBase CreateEmitter(String pEmitterName)
        {
            ParticleEmitterConfig emitterConfig = m_particleEmitterConfigs[pEmitterName];
            ObjectHandle objectHandle = Activator.CreateInstance(null, emitterConfig.ClassHandler);
            ParticleEmitterBase emitterBase = (ParticleEmitterBase)objectHandle.Unwrap();

            // initialize the emitter...
            emitterBase.Initialize(m_Game, emitterConfig);

            // store emitter in out list...
            m_particleEmitterList.Add(emitterBase);

            return emitterBase;
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime, Camera pActiveCamera)
        {
            int i = 0;
            while (i < m_particleEmitterList.Count)
            {
                if (m_particleEmitterList[i].Dead)
                {
                    m_particleEmitterList.RemoveAt(i);
                    continue;
                }
                else
                    m_particleEmitterList[i].Update(gameTime, pActiveCamera);

                i++;
            }
            base.Update(gameTime, pActiveCamera);
        }

        public override void Draw(GameTime gameTime, Camera pActiveCamera)
        {
            foreach (ParticleEmitterBase particleEmitter in m_particleEmitterList)
                particleEmitter.Draw(gameTime, pActiveCamera);

            base.Draw(gameTime, pActiveCamera);
        }

        public void AddParticleEmitter(ParticleEmitterBase pParticleEmitter)
        {
            m_particleEmitterList.Add(pParticleEmitter);
        }

        public void CreateParticleEmitter(String pParticleClass, String pTexture, String pShader, Vector3 pPosition, float pParticleLife, float pSize, float pSpeed, float pEmitInterval, int pParticleMaxCount, float pLife)
        {
            ObjectHandle objectHandle = Activator.CreateInstance("SkyBurner", pParticleClass, new object[] { m_Game });
            ParticleEmitterBase particleEmitter = (ParticleEmitterBase)objectHandle.Unwrap();

            // TOO SLOW
        }
    }
}
